package algorithm2_v3;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Task2 implements Callable<Object> {

	static Logger logger = LoggerFactory.getLogger(Task2.class);

	@Override
	public Object call() throws Exception {
		DatagramSocket socket = new DatagramSocket(12345);
		byte[] buf = new byte[1024];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);
		SystemInfo info = SystemInfo.INSTANCE;
		String sender;
		int val_alive = info.recovered.keySet().size() / 2;
		String machineName = InetAddress.getLocalHost().getHostName();
		ScheduledExecutorService task3 = Executors
				.newSingleThreadScheduledExecutor();
		ScheduledFuture<String> task3Future = null;
		if (info.leader.toString().compareTo(machineName) != 0) {
			task3Future = task3.schedule(new Task3(),
					info.timeout.get(info.leader.toString()),
					TimeUnit.MILLISECONDS);
		}
		while (true) {
			try {
				socket.receive(packet);
				ByteArrayInputStream bais = new ByteArrayInputStream(buf);
				ObjectInputStream ois = new ObjectInputStream(bais);
				// logger.info("Mezuaren zain");
				Message message = (Message) ois.readObject();
				logger.info("Mezua jasota: " + message.sender.toString());
				sender = message.sender.toString();
				if (message.type.equals("RECOVERED")) {
					info.recovered.put(sender, info.recovered.get(sender) + 1);
				} else if (message.type.equals("ALIVE")) {
					info.alive.put(sender, true);
					if (SystemInfo.INSTANCE.leader.toString().equals("")
							&& val_alive <= info.alive.size()) {
						info.leader.replace(0, info.leader.length(),
								machineName);
					}
				} else if (message.type.equals("LEADER")) {
					for (String entry : message.recovered.keySet()) {
						try {
							info.recovered.put(entry, Math.max(
									info.recovered.get(entry),
									message.recovered.get(entry)));
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					info.timeout.put(
							sender,
							Math.max(info.timeout.get(sender),
									info.recovered.get(machineName)));
					if ((SystemInfo.INSTANCE.leader.toString().equals("") && info.recovered
							.get(sender) < info.recovered.get(machineName))
							|| (!SystemInfo.INSTANCE.leader.toString().equals(
									"") && info.recovered.get(sender) <= info.recovered
									.get(info.leader.toString()))) {
						info.leader.replace(0, info.leader.length(), sender);
						// timer reset
						if (task3Future != null) {
							task3Future.cancel(false);
						}
						task3.shutdown();
						task3 = Executors.newSingleThreadScheduledExecutor();
						// logger.info("3. Ataza Martxan");
						try {
							task3Future = task3.schedule(new Task3(),
									info.timeout.get(info.leader.toString()),
									TimeUnit.MILLISECONDS);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					if (SystemInfo.INSTANCE.leader.toString().equals("")
							&& info.recovered.get(machineName) < info.recovered
									.get(info.leader.toString())) {
						info.leader.replace(0, info.leader.length(),
								machineName);
						task3Future.cancel(false);
						task3.shutdown();
					}
				}

			} finally {
				try {
					socket.close();
				} catch (Exception e) {
					logger.info("ERROREA: Task2 socketa ixtean");
					e.printStackTrace();
				}
			}
		}
	}
}
